#include "network/include/VsomeipClient.h"

client_sample::client_sample(bool _use_tcp, const uint8_t& number) 
    : app_(vsomeip::runtime::get()->create_application("Hello")), use_tcp_(_use_tcp), itsServiceNumber(number)
{
    ServiceId    serviceId     = 0x1234;
    InstanceId   instanceId    = 0x5678;
    EventId      eventId1      = 0x0777;
    EventId      eventId2      = 0x1777;
    EventGroupId eventGroupId  = 0x4455;

    for(int i = 0; i < itsServiceNumber; i++)
    {
        itsServiceAttributes.emplace_back(serviceId+i, instanceId, eventId1+i, eventId2+i, eventGroupId+i);
    }
}

bool client_sample::init() 
{
    if (!app_->init()) {
        std::cerr << "Couldn't initialize application" << std::endl;
        return false;
    }
    std::cout << "Client settings [protocol=" << (use_tcp_ ? "TCP" : "UDP") << "]" << std::endl;

    app_->register_state_handler( std::bind(&client_sample::on_state, this, std::placeholders::_1));

    for(const auto& server : itsServiceAttributes)
    {
        app_->register_message_handler(server.serviceId_, server.instanceId_, server.eventIds_[0],
            std::bind(&client_sample::on_event, this, std::placeholders::_1));

        app_->register_message_handler(server.serviceId_, server.instanceId_, server.eventIds_[1],
            std::bind(&client_sample::on_event, this, std::placeholders::_1));
        
        app_->register_availability_handler(server.serviceId_, server.instanceId_,
            std::bind(&client_sample::on_availability, this,
                        std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

        std::set<vsomeip::eventgroup_t> evGroup;
        evGroup.insert(server.eventGroupId_);
        app_->request_event(server.serviceId_, server.instanceId_, server.eventIds_[0],
                evGroup, vsomeip::event_type_e::ET_EVENT);
        app_->request_event(server.serviceId_, server.instanceId_, server.eventIds_[1],
                evGroup, vsomeip::event_type_e::ET_EVENT);
        app_->subscribe(server.serviceId_, server.instanceId_, server.eventGroupId_);
    }

    return true;
}

void client_sample::start() 
{
    app_->start();
}

void client_sample::stop() 
{
    app_->clear_all_handler();

    for(const auto& server : itsServiceAttributes)
    {
        app_->unsubscribe(server.serviceId_, server.instanceId_, server.eventGroupId_);
        app_->release_event(server.serviceId_, server.instanceId_, server.eventIds_[0]);
        app_->release_event(server.serviceId_, server.instanceId_, server.eventIds_[1]);
        app_->release_service(server.serviceId_, server.instanceId_);
    }
    app_->stop();
}

void client_sample::on_state(vsomeip::state_type_e _state) 
{
    if (_state == vsomeip::state_type_e::ST_REGISTERED) 
    {
        for(const auto& server : itsServiceAttributes)
        {
            app_->request_service(server.serviceId_, server.instanceId_);
        }
    }
}

void client_sample::on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) 
{
    std::cout << "Service ["
            << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
            << "] is "
            << (_is_available ? "available." : "NOT available.")
            << std::endl;
}

void client_sample::on_event(const std::shared_ptr<vsomeip::message> &_response) 
{
    std::stringstream its_message;
        its_message << "Received an Event ["
                << std::setw(4)    << std::setfill('0') << std::hex
                << _response->get_service() << "."
                << std::setw(4) << std::setfill('0') << std::hex
                << _response->get_instance() << "."
                << std::setw(4) << std::setfill('0') << std::hex
                << _response->get_method() << "] to Client/Session ["
                << std::setw(4) << std::setfill('0') << std::hex
                << _response->get_client() << "/"
                << std::setw(4) << std::setfill('0') << std::hex
                << _response->get_session()
                << "]";
        std::cout << its_message.str() << std::endl;
}

void client_sample::on_message(const std::shared_ptr<vsomeip::message> &_response) 
{
}

void client_sample::sendRequest()
{

}

